#define WIN32_LEAN_AND_MEAN
#include <windows.h>		// Header File For Windows
#include <GL/glew.h>

#include "common.h"
#include "input.h"
#include "Camera.h"


namespace Tmpl {

static Vec3f gCameraPos(0,0,0);
static Vec3f gCameraRot(0,0,0);
static Matrix4x4f gCameraMatrix;

void Camera::Tick(float deltaTime, float moveSpeed, float rotationSpeed)
{
	gCameraMatrix.Init(Vec3f(0,0,0), -gCameraRot.x, -gCameraRot.y, -gCameraRot.z);

	// Handle camera rotation
	float diffx = 0.0f, diffy = 0.0f;
	if(Tmpl::mouse.IsDown(Tmpl::Mouse::RMB))
	{
		diffx = (float)Tmpl::Clamp(-50, 50, Tmpl::mouse.GetX() - Tmpl::mouse.GetXPrev());
		diffy = (float)Tmpl::Clamp(-50, 50, Tmpl::mouse.GetY() - Tmpl::mouse.GetYPrev());
	}
	if(Tmpl::key.IsDown(Tmpl::TK_LEFT )) diffx -= deltaTime * 200.0f;
	if(Tmpl::key.IsDown(Tmpl::TK_RIGHT)) diffx += deltaTime * 200.0f;
	if(Tmpl::key.IsDown(Tmpl::TK_UP   )) diffy -= deltaTime * 200.0f;
	if(Tmpl::key.IsDown(Tmpl::TK_DOWN )) diffy += deltaTime * 200.0f;

	gCameraRot.y -= diffx * rotationSpeed;
	gCameraRot.x -= diffy * rotationSpeed;
	if(gCameraRot.y < 0)	gCameraRot.y += 360;
	if(gCameraRot.y > 360)	gCameraRot.y -= 360;
	if(gCameraRot.x < 0)	gCameraRot.x += 360;
	if(gCameraRot.x > 360)	gCameraRot.x -= 360;
	//if(gCameraRot.x < -85)	gCameraRot.x = -85;
	//if(gCameraRot.x > 85)	gCameraRot.x = 85;
                  
	// Handle camera movement
	Matrix4x4f rot = gCameraMatrix; rot.Invert();

	if(Tmpl::key.IsDown(Tmpl::TK_SHIFT)) moveSpeed *= 10.0f;
	const Vec3f X = rot.Transform(Vec3f(1,0,0));
	const Vec3f Y = rot.Transform(Vec3f(0,1,0));
	const Vec3f Z = rot.Transform(Vec3f(0,0,1));
	const float dist = deltaTime * moveSpeed;

	if(Tmpl::key.IsDown('A')) gCameraPos -= dist * X;
	if(Tmpl::key.IsDown('D')) gCameraPos += dist * X;
	if(Tmpl::key.IsDown('E')) gCameraPos -= dist * Y;
	if(Tmpl::key.IsDown('Q')) gCameraPos += dist * Y;
	if(Tmpl::key.IsDown('W')) gCameraPos -= dist * Z;
	if(Tmpl::key.IsDown('S')) gCameraPos += dist * Z;

	gCameraMatrix.Init(Vec3f(0,0,0), -gCameraRot.x, -gCameraRot.y, -gCameraRot.z);
}

void Camera::SetPos(const Vec3f& pos)
{
	gCameraPos = pos;
}

void Camera::SetRot(const Vec3f& rot)
{
	gCameraRot = rot;
}

Vec3f Camera::GetPos()
{
	return gCameraPos;
}

Vec3f Camera::GetRot()
{
	return gCameraRot;
}

Vec3f Camera::GetFacing()
{
	Vec3f facing = Vec3f(0,0,-1);
	facing = gCameraMatrix.Transform(facing);
	return facing.Normalized();
}

Matrix4x4f Camera::GetMatrix()
{
	Matrix4x4f mat = gCameraMatrix;
	mat.Translate(-gCameraPos);
	return mat;
}
Matrix4x4f Camera::GetRotMatrix()
{
	return gCameraMatrix;
}
void Camera::ApplyOpenglMatrix()
{
	glLoadIdentity();
	glMultMatrixf(gCameraMatrix);
	glTranslatef(-gCameraPos.x, -gCameraPos.y, -gCameraPos.z);
}

}